package com.huaxin.hxfiles.controller;

import com.huaxin.hxfiles.common.FileUtils;
import com.huaxin.hxfiles.dto.request.Base64ImageUploadReqDTO;
import com.huaxin.hxfiles.dto.response.UploadFIleRespDTO;
import com.huaxin.hxfiles.models.ResponseCode;
import com.huaxin.hxfiles.models.ResponseResult;
import com.huaxin.hxfiles.service.FileUploadService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.UUID;

@Tag(name = "文件服务")
@RestController
@RequestMapping("/v1/files")
public class FilesController {
    private static final Logger logger = LoggerFactory.getLogger(FilesController.class);
    @Value("${upload.downDomainName}")
    private String downDomainName;
    private final FileUploadService fileUploadService;

    @Autowired
    public FilesController(FileUploadService fileUploadService) {
        this.fileUploadService = fileUploadService;
    }

    // 上传文件
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd"); // 按日期分目录

    @Operation(summary = "上传文件", description = "上传文件")
    @PostMapping("/uploadFile")
    public ResponseResult<UploadFIleRespDTO> uploadFile(@RequestParam("file") MultipartFile multipartFile) {

        try {
            // --- 1. 保存临时文件 ---
            Path tempFile = Files.createTempFile("upload", "-" + multipartFile.getOriginalFilename());
            try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) {
                fos.write(multipartFile.getBytes());
            }
            // --- 2. 生成唯一且安全的目标文件名和路径 ---
            // 2.1 获取原始文件信息
            String originalFilename = multipartFile.getOriginalFilename();
            String fileExtension = ""; // 文件扩展名 (带点)
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            // 日期目录 + UUID (便于管理)
            String datePath = LocalDateTime.now().format(DATE_FORMATTER); // 例如: 2025/08/18
            String uniqueFileName = UUID.randomUUID().toString() + fileExtension;
            String targetPath = "uploads/" + datePath + "/" + uniqueFileName; // 例如: uploads/2025/08/18/a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8.png
            // --- 3. 上传到 MinIO ---
            fileUploadService.upload(targetPath, tempFile.toString());
            // --- 4. 删除临时文件 ---
            Files.deleteIfExists(tempFile);
            // --- 5. 构造响应 DTO ---
            UploadFIleRespDTO uploadFIleRespDTO = new UploadFIleRespDTO();
            // **关键：返回原始文件名给前端显示，但存储用的是唯一文件名**
            uploadFIleRespDTO.setFileName(targetPath);
            uploadFIleRespDTO.setFileType(fileExtension); // 如 .docx, .png
            uploadFIleRespDTO.setFileSize(FileUtils.formatFileSize(multipartFile.getSize()));
            uploadFIleRespDTO.setDomainName(downDomainName);

            return ResponseResult.ok(uploadFIleRespDTO);

        } catch (Exception e) {
            return ResponseResult.failure(ResponseCode.INTERNAL_ERROR, "上传文件失败。", null);
        }
    }

    // ------------------------------
// 新增接口：上传 Base64 图片
// ------------------------------
    @Operation(summary = "上传 Base64 图片", description = "上传 Base64 编码的图片数据，支持 data:image/xxx;base64, 格式")
    @PostMapping("/uploadBase64Image")
    public ResponseResult<UploadFIleRespDTO> uploadBase64Image(@RequestBody @Valid Base64ImageUploadReqDTO dto) {
        try {
            String base64Data = dto.getBase64Data();

            // 1. 提取 Base64 内容（去除 data:image/xxx;base64, 前缀）
            String base64Content = base64Data;
            if (base64Data.contains(",")) {
                base64Content = base64Data.split(",", 2)[1]; // 取逗号后的部分
            }

            // 2. Base64 解码
            byte[] imageData;
            try {
                imageData = Base64.getDecoder().decode(base64Content);
            } catch (IllegalArgumentException e) {
                return ResponseResult.failure(ResponseCode.BAD_REQUEST, "Base64 格式无效", null);
            }

            // 3. 文件大小校验（KB）
            int fileSizeKB = imageData.length / 1024;
            if (fileSizeKB > dto.getMaxSizeKB()) {
                return ResponseResult.failure(ResponseCode.BAD_REQUEST, "图片大小超过限制（" + dto.getMaxSizeKB() + "KB）", null);
            }

            // 4. 推断图片类型和扩展名
            String mimeType = getImageMimeType(base64Data);
            String fileExtension = getFileExtensionByMimeType(mimeType);
            if (fileExtension == null) {
                return ResponseResult.failure(ResponseCode.BAD_REQUEST, "不支持的图片格式", null);
            }

            // 5. 生成唯一路径
            String datePath = LocalDateTime.now().format(DATE_FORMATTER);
            String uniqueFileName = UUID.randomUUID().toString() + fileExtension;
            String targetPath = "uploads/" + datePath + "/" + uniqueFileName;

            // 6. 上传到 MinIO
            fileUploadService.upload(targetPath, imageData);

            // 7. 构造响应
            UploadFIleRespDTO respDTO = new UploadFIleRespDTO();
            respDTO.setFileName(targetPath);           // 存储路径
            respDTO.setFileType(fileExtension);        // .png, .jpg 等
            respDTO.setFileSize(FileUtils.formatFileSize(imageData.length));
            respDTO.setDomainName(downDomainName);
            // 如果返回的是签名 URL，这里调用 getDownloadUrl
            // respDTO.setFileUrl(fileUploadService.getDownloadUrl(targetPath));
            // 否则拼接：
            respDTO.setFileUrl(downDomainName + "/" + targetPath);

            return ResponseResult.ok(respDTO);

        } catch (Exception e) {
            logger.error("Base64 图片上传失败: ", e);
            return ResponseResult.failure(ResponseCode.INTERNAL_ERROR, "上传图片失败：" + e.getMessage(), null);
        }
    }

    /**
     * 获取图片的 MIME 类型
     *
     * @param base64Data Base64 数据
     * @return MIME 类型
     */
    private String getImageMimeType(String base64Data) {
        if (base64Data.startsWith("data:image/png;")) return "image/png";
        if (base64Data.startsWith("data:image/jpeg;")) return "image/jpeg";
        if (base64Data.startsWith("data:image/jpg;")) return "image/jpg";
        if (base64Data.startsWith("data:image/gif;")) return "image/gif";
        if (base64Data.startsWith("data:image/webp;")) return "image/webp";
        return "image/png"; // 默认
    }

    /**
     * 根据 MIME 类型获取文件扩展名
     *
     * @param mimeType MIME 类型
     * @return 文件扩展名
     */
    private String getFileExtensionByMimeType(String mimeType) {
        return switch (mimeType.toLowerCase()) {
            case "image/png" -> ".png";
            case "image/jpeg", "image/jpg" -> ".jpg";
            case "image/gif" -> ".gif";
            case "image/webp" -> ".webp";
            default -> null;
        };
    }

    // (可选) 文件扩展名白名单校验方法
    private boolean isValidExtension(String extension) {
        if (extension == null || extension.isEmpty()) return false;
        String[] allowedExtensions = {".jpg", ".jpeg", ".png", ".gif", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".txt"};
        for (String allowed : allowedExtensions) {
            if (allowed.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }


    // 删除文件
    @DeleteMapping("/delete")
    @Operation(summary = "删除文件", description = "删除文件")
    public ResponseResult<String> deleteFile(@Parameter(description = "文件名", required = true)
                                             @RequestParam String filePath) {
        try {
            boolean success = fileUploadService.delete(filePath);
            if (success) {
                return ResponseResult.ok("文件删除成功");
            } else {
                return ResponseResult.failure(ResponseCode.INTERNAL_ERROR, "删除文件失败。", null);
            }
        } catch (Exception e) {
            logger.error("文件删除失败: ", e);
            return ResponseResult.failure(ResponseCode.INTERNAL_ERROR, "删除文件失败。", null);
        }
    }

    // 获取文件安全下载链接
    @GetMapping("/downloadUrl")
    @Operation(summary = "获取文件安全下载链接", description = "获取文件安全下载链接")
    public ResponseResult<String> getDownloadUrl(@Parameter(description = "文件名") @RequestParam String filePath) {
        try {
            return ResponseResult.ok(fileUploadService.getDownloadUrl(filePath));
        } catch (Exception e) {
            logger.error("获取下载链接失败: ", e);
            return ResponseResult.failure(ResponseCode.INTERNAL_ERROR, "获取下载链接失败。", null);
        }
    }
}
